package cn.edu.guet.springmvcdemo.mvc;

import cn.edu.guet.springmvcdemo.ioc.BeanFactory;
import com.google.gson.GsonBuilder;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@WebServlet(value = "*.do")
public class DispatcherServlet extends HttpServlet {
    Map<String, ControllerMapping> controllerMappingMap;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        controllerMappingMap = (Map<String, ControllerMapping>) config.getServletContext().getAttribute("cn.edu.guet.springmvcdemo.controller");
        System.out.println("from application scope read:"+controllerMappingMap);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        ControllerMapping mapping = null;
        String requestURL = request.getRequestURI();
//        System.out.println("请求地址:"+requestURL);
        requestURL = requestURL.substring(requestURL.indexOf("/", 1) + 1);
//        requestURL = StringUtils.substringBetween(requestURL, request.getContextPath(), ".do");
        System.out.println("去掉前缀:" + requestURL);
        if (controllerMappingMap.containsKey(requestURL)) {
            mapping = controllerMappingMap.get(requestURL);
        }
        Class controllerClass = mapping.getControllerClass();
        Method handleMethod = mapping.getHandleMethod();
        Class[] parameterType = handleMethod.getParameterTypes();

        /*
        反射获取参数名称
         */
        List<String> parameterList = new ArrayList<>();
        Parameter[] parameters = handleMethod.getParameters();
        for (Parameter params : parameters) {
            parameterList.add(params.getName());
        }

        Object[] parameterValues = new Object[parameterType.length];
        Object obj = null;

        String controllerClassName = controllerClass.getSimpleName();
        controllerClassName = controllerClassName.substring(0, 1).toLowerCase() + controllerClassName.substring(1);//将首字母变为小写
//        System.out.println(controllerClassName);
        obj = BeanFactory.getInstance().getBean(controllerClassName);
        try {
            for (int i = 0; i < parameterType.length; i++) {
                if (ClassUtils.isAssignable(parameterType[i], HttpServletRequest.class)) {
                    parameterValues[i] = request;
                } else if (ClassUtils.isAssignable(parameterType[i], HttpServletResponse.class)) {
                    parameterValues[i] = response;
                } else if (ClassUtils.isAssignable(parameterType[i], HttpSession.class)) {
                    parameterValues[i] = request.getSession();
                } else if (parameterType[i].isPrimitive()) {//如果是基本类型
                    if (parameterType[i].getTypeName().equals("int")) {
                        parameterValues[i] = Integer.parseInt(request.getParameter(parameterList.get(i)));
                    } else if (parameterType[i].getTypeName().equals("float")) {
                        parameterValues[i] = Float.parseFloat(request.getParameter(parameterList.get(i)));
                    } else if (parameterType[i].getTypeName().equals("double")) {
                        parameterValues[i] = Double.parseDouble(request.getParameter(parameterList.get(i)));
                    } else if (parameterType[i].getTypeName().equals("byte")) {
                        parameterValues[i] = Byte.parseByte(request.getParameter(parameterList.get(i)));
                    } else if (parameterType[i].getTypeName().equals("short")) {
                        parameterValues[i] = Short.parseShort(request.getParameter(parameterList.get(i)));
                    } else if (parameterType[i].getTypeName().equals("long")) {
                        parameterValues[i] = Long.parseLong(request.getParameter(parameterList.get(i)));
                    } else if (parameterType[i].getTypeName().equals("boolean")) {
                        parameterValues[i] = Boolean.parseBoolean(request.getParameter(parameterList.get(i)));
                    } else {    //以上都不是的话，就只能是char型了
                        parameterValues[i] = request.getParameter(parameterList.get(i));
                    }
                } else if (ClassUtils.isAssignable(parameterType[i], String.class)) {
                    parameterValues[i] = request.getParameter(parameterList.get(i));
                } else {
                    //Bean
                    Object pojo = parameterType[i].newInstance();
                    //得到请求里所有的参数：Map<参数名, value>
                    //获取表单里的数据
                    Map<String, String[]> parameterMap = request.getParameterMap();
                    //beanutils会自动将map里的key与bean的属性名进行反射赋值
                    BeanUtils.populate(pojo, parameterMap);
                    parameterValues[i] = pojo;
                }
            }
            //通过反射调用方法，并赋值
            Object returnValue = handleMethod.invoke(obj, parameterValues);
            if (returnValue != null && returnValue instanceof String) { //方法返回的是一个字符串类
                String path = returnValue.toString();
                if (StringUtils.startsWith(path, "redirect:")) {
                    //重定向
                    response.sendRedirect(request.getContextPath() + StringUtils.substringAfter(path, "redirect:"));
                } else {
                    //转发
                    request.getRequestDispatcher(StringUtils.substringAfter(path, ":")).forward(request, response);
                }
            } else if (returnValue != null && !(returnValue instanceof String)) {
                response.setContentType("application/json; charset=UTF-8");
                //返回的是一个bean，即客户端发送的是ajax请求，并将该bean转换成json
                String json = new GsonBuilder()
                        .setDateFormat("yyyy-MM-dd HH:mm:ss")
                        .setPrettyPrinting()
                        .create()
                        .toJson(returnValue);
                PrintWriter out = response.getWriter();
                out.write(json);
                out.flush();
                out.close();
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
